Completed
Push — master ( 8967bc...e88c19 )
by Rain
02:47
created

Attachment.js ➔ ???   D

Complexity

Conditions 15
Paths 15

Size

Total Lines 104

Duplication

Lines 0
Ratio 0 %

Importance

Changes 27
Bugs 0 Features 0
Metric Value
cc 15
c 27
b 0
f 0
nc 15
nop 2
dl 0
loc 104
rs 4.9121

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like Attachment.js ➔ ??? often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
2
import window from 'window';
3
import _ from '_';
4
import ko from 'ko';
5
6
import {FileType} from 'Common/Enums';
7
import {bAllowPdfPreview, data as GlobalsData} from 'Common/Globals';
8
import {trim, pInt, inArray, isNonEmptyArray, getFileExtension, friendlySize} from 'Common/Utils';
9
import {attachmentDownload, attachmentPreview, attachmentFramed, attachmentPreviewAsPlain, attachmentThumbnailPreview} from 'Common/Links';
10
11
import {AbstractModel} from 'Knoin/AbstractModel';
12
13
import Audio from 'Common/Audio';
14
15
/**
16
 * @param {string} sExt
0 ignored issues
show
Documentation introduced by
The parameter sExt does not exist. Did you maybe forget to remove this comment?
Loading history...
17
 * @param {string} sMimeType
0 ignored issues
show
Documentation introduced by
The parameter sMimeType does not exist. Did you maybe forget to remove this comment?
Loading history...
18
 * @returns {string}
19
 */
20
export const staticFileType = _.memoize((ext, mimeType) => {
21
	ext = trim(ext).toLowerCase();
22
	mimeType = trim(mimeType).toLowerCase();
23
24
	let result = FileType.Unknown;
0 ignored issues
show
Unused Code introduced by
The assignment to variable result seems to be never used. Consider removing it.
Loading history...
25
	const mimeTypeParts = mimeType.split('/');
26
27
	switch (true)
28
	{
29
		case 'image' === mimeTypeParts[0] || -1 < inArray(ext, [
30
			'png', 'jpg', 'jpeg', 'gif', 'bmp'
31
		]):
32
			result = FileType.Image;
33
			break;
34
		case 'audio' === mimeTypeParts[0] || -1 < inArray(ext, [
35
			'mp3', 'ogg', 'oga', 'wav'
36
		]):
37
			result = FileType.Audio;
38
			break;
39
		case 'video' === mimeTypeParts[0] || -1 < inArray(ext, [
40
			'mkv', 'avi'
41
		]):
42
			result = FileType.Video;
43
			break;
44
		case -1 < inArray(ext, [
45
			'php', 'js', 'css'
46
		]):
47
			result = FileType.Code;
48
			break;
49
		case 'eml' === ext || -1 < inArray(mimeType, [
50
			'message/delivery-status', 'message/rfc822'
51
		]):
52
			result = FileType.Eml;
53
			break;
54
		case ('text' === mimeTypeParts[0] && 'html' !== mimeTypeParts[1]) || -1 < inArray(ext, [
55
			'txt', 'log'
56
		]):
57
			result = FileType.Text;
58
			break;
59
		case ('text/html' === mimeType) || -1 < inArray(ext, [
60
			'html'
61
		]):
62
			result = FileType.Html;
63
			break;
64
		case -1 < inArray(mimeTypeParts[1], [
65
			'zip', '7z', 'tar', 'rar', 'gzip', 'bzip', 'bzip2', 'x-zip', 'x-7z', 'x-rar', 'x-tar', 'x-gzip', 'x-bzip', 'x-bzip2', 'x-zip-compressed', 'x-7z-compressed', 'x-rar-compressed'
66
		]) || -1 < inArray(ext, [
67
			'zip', '7z', 'tar', 'rar', 'gzip', 'bzip', 'bzip2'
68
		]):
69
			result = FileType.Archive;
70
			break;
71
		case -1 < inArray(mimeTypeParts[1], ['pdf', 'x-pdf']) || -1 < inArray(ext, [
72
			'pdf'
73
		]):
74
			result = FileType.Pdf;
75
			break;
76
		case -1 < inArray(mimeType, [
77
			'application/pgp-signature', 'application/pgp-keys'
78
		]) || -1 < inArray(ext, [
79
			'asc', 'pem', 'ppk'
80
		]):
81
			result = FileType.Certificate;
82
			break;
83
		case -1 < inArray(mimeType, ['application/pkcs7-signature']) ||
84
			-1 < inArray(ext, ['p7s']):
85
86
			result = FileType.CertificateBin;
87
			break;
88
		case -1 < inArray(mimeTypeParts[1], [
89
			'rtf', 'msword', 'vnd.msword', 'vnd.openxmlformats-officedocument.wordprocessingml.document',
90
			'vnd.openxmlformats-officedocument.wordprocessingml.template',
91
			'vnd.ms-word.document.macroEnabled.12',
92
			'vnd.ms-word.template.macroEnabled.12'
93
		]):
94
			result = FileType.WordText;
95
			break;
96
		case -1 < inArray(mimeTypeParts[1], [
97
			'excel', 'ms-excel', 'vnd.ms-excel',
98
			'vnd.openxmlformats-officedocument.spreadsheetml.sheet',
99
			'vnd.openxmlformats-officedocument.spreadsheetml.template',
100
			'vnd.ms-excel.sheet.macroEnabled.12',
101
			'vnd.ms-excel.template.macroEnabled.12',
102
			'vnd.ms-excel.addin.macroEnabled.12',
103
			'vnd.ms-excel.sheet.binary.macroEnabled.12'
104
		]):
105
			result = FileType.Sheet;
106
			break;
107
		case -1 < inArray(mimeTypeParts[1], [
108
			'powerpoint', 'ms-powerpoint', 'vnd.ms-powerpoint',
109
			'vnd.openxmlformats-officedocument.presentationml.presentation',
110
			'vnd.openxmlformats-officedocument.presentationml.template',
111
			'vnd.openxmlformats-officedocument.presentationml.slideshow',
112
			'vnd.ms-powerpoint.addin.macroEnabled.12',
113
			'vnd.ms-powerpoint.presentation.macroEnabled.12',
114
			'vnd.ms-powerpoint.template.macroEnabled.12',
115
			'vnd.ms-powerpoint.slideshow.macroEnabled.12'
116
		]):
117
			result = FileType.Presentation;
118
			break;
119
		// no default
120
	}
121
122
	return result;
123
});
124
125
/**
126
 * @param {string} sFileType
0 ignored issues
show
Documentation introduced by
The parameter sFileType does not exist. Did you maybe forget to remove this comment?
Loading history...
127
 * @returns {string}
128
 */
129
export const staticIconClass = _.memoize((fileType) => {
0 ignored issues
show
Unused Code introduced by
The constant staticIconClass seems to be never used. Consider removing it.
Loading history...
130
	let
131
		resultText = '',
132
		resultClass = 'icon-file';
0 ignored issues
show
Unused Code introduced by
The assignment to variable resultClass seems to be never used. Consider removing it.
Loading history...
133
134 View Code Duplication
	switch (fileType)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
135
	{
136
		case FileType.Text:
137
		case FileType.Eml:
138
		case FileType.WordText:
139
			resultClass = 'icon-file-text';
140
			break;
141
		case FileType.Html:
142
		case FileType.Code:
143
			resultClass = 'icon-file-code';
144
			break;
145
		case FileType.Image:
146
			resultClass = 'icon-file-image';
147
			break;
148
		case FileType.Audio:
149
			resultClass = 'icon-file-music';
150
			break;
151
		case FileType.Video:
152
			resultClass = 'icon-file-movie';
153
			break;
154
		case FileType.Archive:
155
			resultClass = 'icon-file-zip';
156
			break;
157
		case FileType.Certificate:
158
		case FileType.CertificateBin:
159
			resultClass = 'icon-file-certificate';
160
			break;
161
		case FileType.Sheet:
162
			resultClass = 'icon-file-excel';
163
			break;
164
		case FileType.Presentation:
165
			resultClass = 'icon-file-chart-graph';
166
			break;
167
		case FileType.Pdf:
168
			resultText = 'pdf';
169
			resultClass = 'icon-none';
170
			break;
171
		// no default
172
	}
173
174
	return [resultClass, resultText];
175
});
176
177
/**
178
 * @static
179
 * @param {string} sFileType
0 ignored issues
show
Documentation introduced by
The parameter sFileType does not exist. Did you maybe forget to remove this comment?
Loading history...
180
 * @returns {string}
181
 */
182
export const staticCombinedIconClass = (data) => {
0 ignored issues
show
Unused Code introduced by
The constant staticCombinedIconClass seems to be never used. Consider removing it.
Loading history...
183
	let
184
		result = '',
185
		types = [];
0 ignored issues
show
Unused Code introduced by
The assignment to variable types seems to be never used. Consider removing it.
Loading history...
186
187
	if (isNonEmptyArray(data))
188
	{
189
		result = 'icon-attachment';
190
		types = _.uniq(_.compact(_.map(data, (item) => (item ? staticFileType(getFileExtension(item[0]), item[1]) : ''))));
0 ignored issues
show
Bug introduced by
The variable item seems to be never initialized.
Loading history...
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
191
192
		if (types && 1 === types.length && types[0])
193
		{
194 View Code Duplication
			switch (types[0])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
195
			{
196
				case FileType.Text:
197
				case FileType.WordText:
198
					result = 'icon-file-text';
199
					break;
200
				case FileType.Html:
201
				case FileType.Code:
202
					result = 'icon-file-code';
203
					break;
204
				case FileType.Image:
205
					result = 'icon-file-image';
206
					break;
207
				case FileType.Audio:
208
					result = 'icon-file-music';
209
					break;
210
				case FileType.Video:
211
					result = 'icon-file-movie';
212
					break;
213
				case FileType.Archive:
214
					result = 'icon-file-zip';
215
					break;
216
				case FileType.Certificate:
217
				case FileType.CertificateBin:
218
					result = 'icon-file-certificate';
219
					break;
220
				case FileType.Sheet:
221
					result = 'icon-file-excel';
222
					break;
223
				case FileType.Presentation:
224
					result = 'icon-file-chart-graph';
225
					break;
226
				// no default
227
			}
228
		}
229
	}
230
231
	return result;
232
};
233
234
class AttachmentModel extends AbstractModel
235
{
236
	constructor() {
237
		super('AttachmentModel');
238
239
		this.checked = ko.observable(false);
240
241
		this.mimeType = '';
242
		this.fileName = '';
243
		this.fileNameExt = '';
244
		this.fileType = FileType.Unknown;
245
		this.estimatedSize = 0;
246
		this.friendlySize = '';
247
		this.isInline = false;
248
		this.isLinked = false;
249
		this.isThumbnail = false;
250
		this.cid = '';
251
		this.cidWithOutTags = '';
252
		this.contentLocation = '';
253
		this.download = '';
254
		this.folder = '';
255
		this.uid = '';
256
		this.mimeIndex = '';
257
		this.framed = false;
258
	}
259
260
	/**
261
	 * @static
262
	 * @param {AjaxJsonAttachment} json
263
	 * @returns {?AttachmentModel}
264
	 */
265
	static newInstanceFromJson(json) {
266
		const attachment = new AttachmentModel();
267
		return attachment.initByJson(json) ? attachment : null;
268
	}
269
270
	/**
271
	 * @param {AjaxJsonAttachment} json
272
	 * @returns {boolean}
273
	 */
274
	initByJson(json) {
275
		let bResult = false;
276
		if (json && 'Object/Attachment' === json['@Object'])
277
		{
278
			this.mimeType = trim((json.MimeType || '').toLowerCase());
279
			this.fileName = trim(json.FileName);
280
			this.estimatedSize = pInt(json.EstimatedSize);
281
			this.isInline = !!json.IsInline;
282
			this.isLinked = !!json.IsLinked;
283
			this.isThumbnail = !!json.IsThumbnail;
284
			this.cid = json.CID;
285
			this.contentLocation = json.ContentLocation;
286
			this.download = json.Download;
287
288
			this.folder = json.Folder;
289
			this.uid = json.Uid;
290
			this.mimeIndex = json.MimeIndex;
291
			this.framed = !!json.Framed;
292
293
			this.friendlySize = friendlySize(this.estimatedSize);
294
			this.cidWithOutTags = this.cid.replace(/^<+/, '').replace(/>+$/, '');
295
296
			this.fileNameExt = getFileExtension(this.fileName);
297
			this.fileType = staticFileType(this.fileNameExt, this.mimeType);
298
299
			bResult = true;
300
		}
301
302
		return bResult;
303
	}
304
305
	/**
306
	 * @returns {boolean}
307
	 */
308
	isImage() {
309
		return FileType.Image === this.fileType;
310
	}
311
312
	/**
313
	 * @returns {boolean}
314
	 */
315
	isMp3() {
316
		return FileType.Audio === this.fileType && 'mp3' === this.fileNameExt;
317
	}
318
319
	/**
320
	 * @returns {boolean}
321
	 */
322
	isOgg() {
323
		return FileType.Audio === this.fileType && ('oga' === this.fileNameExt || 'ogg' === this.fileNameExt);
324
	}
325
326
	/**
327
	 * @returns {boolean}
328
	 */
329
	isWav() {
330
		return FileType.Audio === this.fileType && 'wav' === this.fileNameExt;
331
	}
332
333
	/**
334
	 * @returns {boolean}
335
	 */
336
	hasThumbnail() {
337
		return this.isThumbnail;
338
	}
339
340
	/**
341
	 * @returns {boolean}
342
	 */
343
	isText() {
344
		return FileType.Text === this.fileType || FileType.Eml === this.fileType ||
345
			FileType.Certificate === this.fileType || FileType.Html === this.fileType || FileType.Code === this.fileType;
346
	}
347
348
	/**
349
	 * @returns {boolean}
350
	 */
351
	isPdf() {
352
		return FileType.Pdf === this.fileType;
353
	}
354
355
	/**
356
	 * @returns {boolean}
357
	 */
358
	isFramed() {
359
		return this.framed && (GlobalsData.__APP__ && GlobalsData.__APP__.googlePreviewSupported()) &&
360
			!(this.isPdf() && bAllowPdfPreview) && !this.isText() && !this.isImage();
361
	}
362
363
	/**
364
	 * @returns {boolean}
365
	 */
366
	hasPreview() {
367
		return this.isImage() || (this.isPdf() && bAllowPdfPreview) || this.isText() || this.isFramed();
368
	}
369
370
	/**
371
	 * @returns {boolean}
372
	 */
373
	hasPreplay() {
374
		return (Audio.supportedMp3 && this.isMp3()) || (Audio.supportedOgg && this.isOgg()) || (Audio.supportedWav && this.isWav());
375
	}
376
377
	/**
378
	 * @returns {string}
379
	 */
380
	linkDownload() {
381
		return attachmentDownload(this.download);
382
	}
383
384
	/**
385
	 * @returns {string}
386
	 */
387
	linkPreview() {
388
		return attachmentPreview(this.download);
389
	}
390
391
	/**
392
	 * @returns {string}
393
	 */
394
	linkThumbnail() {
395
		return this.hasThumbnail() ? attachmentThumbnailPreview(this.download) : '';
396
	}
397
398
	/**
399
	 * @returns {string}
400
	 */
401
	linkThumbnailPreviewStyle() {
402
		const link = this.linkThumbnail();
403
		return '' === link ? '' : 'background:url(' + link + ')';
404
	}
405
406
	/**
407
	 * @returns {string}
408
	 */
409
	linkFramed() {
410
		return attachmentFramed(this.download);
411
	}
412
413
	/**
414
	 * @returns {string}
415
	 */
416
	linkPreviewAsPlain() {
417
		return attachmentPreviewAsPlain(this.download);
418
	}
419
420
	/**
421
	 * @returns {string}
422
	 */
423
	linkPreviewMain() {
424
		let result = '';
425
		switch (true)
426
		{
427
			case this.isImage():
428
			case this.isPdf() && bAllowPdfPreview:
429
				result = this.linkPreview();
430
				break;
431
			case this.isText():
432
				result = this.linkPreviewAsPlain();
433
				break;
434
			case this.isFramed():
435
				result = this.linkFramed();
436
				break;
437
			// no default
438
		}
439
440
		return result;
441
	}
442
443
	/**
444
	 * @returns {string}
445
	 */
446
	generateTransferDownloadUrl() {
447
		let link = this.linkDownload();
448
		if ('http' !== link.substr(0, 4))
449
		{
450
			link = window.location.protocol + '//' + window.location.host + window.location.pathname + link;
451
		}
452
453
		return this.mimeType + ':' + this.fileName + ':' + link;
454
	}
455
456
	/**
457
	 * @param {AttachmentModel} attachment
458
	 * @param {*} event
459
	 * @returns {boolean}
460
	 */
461
	eventDragStart(attachment, event) {
462
		const localEvent = event.originalEvent || event;
463
		if (attachment && localEvent && localEvent.dataTransfer && localEvent.dataTransfer.setData)
464
		{
465
			localEvent.dataTransfer.setData('DownloadURL', this.generateTransferDownloadUrl());
466
		}
467
468
		return true;
469
	}
470
471
	/**
472
	 * @returns {string}
473
	 */
474
	iconClass() {
475
		return staticIconClass(this.fileType)[0];
476
	}
477
478
	/**
479
	 * @returns {string}
480
	 */
481
	iconText() {
482
		return staticIconClass(this.fileType)[1];
483
	}
484
}
485
486
export {AttachmentModel, AttachmentModel as default};
487